/*
 * gf.h
 *
 * External include file for Galois field arithmetic.
 */

#pragma once

#include <stdint.h>

#ifdef  INTEL_SSE4
#include <nmmintrin.h>
#include <emmintrin.h>
#endif

#define GALOIS_MULT_HALF_TABLE  0x100
#define GALOIS_MULT_FULL_TABLE  0x200
#define GALOIS_MULT_LOG         0x400
#define GALOIS_MULT_SHIFT       0x800
#define GALOIS_MULT_VEC         0x1000
#define GALOIS_MULT_BYTWO       0x2000
#define GALOIS_MULT_LAZY        0x4000

/*
 * Note that we don't define addition functions.  Addition (and subtraction)
 * is done by XOR, and we don't need a routine to do XOR...
 */

typedef uint8_t     gf_val_8_t;
typedef uint8_t     gf_val_4_t;
typedef uint16_t    gf_val_16_t;

typedef struct galois_field_8 {
    uint32_t    flags;
    struct gf_data  *data;
    void		(*mult_buf_const)(const struct galois_field_8 *gf, const gf_val_8_t *buf, gf_val_8_t c, gf_val_8_t *result, int len);
    void		(*mult_buf_buf)(const struct galois_field_8 *gf, const gf_val_8_t *buf1, const gf_val_8_t *buf2, gf_val_8_t *result, int len);
    void        (*mult_acc_buf)(const struct galois_field_8 *gf, const gf_val_8_t *buf, gf_val_8_t factors[], gf_val_8_t *accs[], int len, int naccs);
    void        (*mult_acc_sig)(const struct galois_field_8 *gf, const gf_val_8_t *buf, gf_val_8_t alpha, gf_val_8_t *sig, int sig_width, int len);
    gf_val_8_t  (*mult)(const struct galois_field_8 *gf, gf_val_8_t a, gf_val_8_t b);
    gf_val_8_t  (*divide)(const struct galois_field_8 *gf, gf_val_8_t a, gf_val_8_t b);
    gf_val_8_t  (*invert)(const struct galois_field_8 *gf, gf_val_8_t a);
    gf_val_8_t  (*log)(const struct galois_field_8 *gf, gf_val_8_t a);
    gf_val_8_t  (*pow)(const struct galois_field_8 *gf, gf_val_8_t a, uint32_t x);
    gf_val_8_t  (*antilog)(const struct galois_field_8 *gf, gf_val_8_t a);
} galois_field_8_t;

typedef galois_field_8_t galois_field_4_t;

typedef struct galois_field_16 {
    uint32_t    flags;
    uint32_t    prim_poly;
    struct gf_data  *data;
    void		(*mult_buf_const)(const struct galois_field_16 *gf, const gf_val_16_t *buf, gf_val_16_t c, gf_val_16_t *result, int len);
    void		(*mult_buf_buf)(const struct galois_field_16 *gf, const gf_val_16_t *buf1, const gf_val_16_t *buf2, gf_val_16_t *result, int len);
    void        (*mult_acc_buf)(const struct galois_field_16 *gf, const gf_val_16_t *buf, gf_val_16_t factors[], gf_val_16_t *accs[], int len, int naccs);
    gf_val_16_t  (*mult)(const struct galois_field_16 *gf, gf_val_16_t a, gf_val_16_t b);
    gf_val_16_t  (*divide)(const struct galois_field_16 *gf, gf_val_16_t a, gf_val_16_t b);
    gf_val_16_t  (*invert)(const struct galois_field_16 *gf, gf_val_16_t a);
    gf_val_16_t  (*log)(const struct galois_field_16 *gf, gf_val_16_t a);
    gf_val_16_t  (*antilog)(const struct galois_field_16 *gf, gf_val_16_t a);
} galois_field_16_t;

extern int	gf_w8_init (galois_field_8_t *gf, uint32_t flags);
extern void	gf_w8_free (galois_field_8_t *gf);
extern int  gf_w8_unit_test ();

extern int	gf_w16_init (galois_field_16_t *gf, uint32_t flags);
extern void	gf_w16_free (galois_field_16_t *gf);
extern int  gf_w16_unit_test ();

